﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Linq.SqlClient;
using System.Linq;
using System.Text;
using CHILIS.Componentes.CoreRestaurant.Model.Adquicisiones;
using CHILIS.Componentes.CoreRestaurant.Logic.Singleton;


namespace CHILIS.Componentes.CoreRestaurant.Logic.Facade
{
    public static class Insumo
    {
        /// <summary>
        /// Se registra la solicitud de insumo
        /// </summary>
        /// <param name="Numero_Solicitud">Número de la Solicitud</param>
        /// <param name="Tipo_Solicitud">Tipo de Solicitud</param>
        /// <param name="Fecha_Solicitud">Fecha de Solicitud</param>
        /// <param name="Fecha_Entrega">Fecha de Entrega</param>
        /// <param name="Descripcion">Descripción de la Solicitud de Insumo</param>
        /// <param name="DetalleInsumos">Listado de detalla de la solicitud de insumo</param>
        /// <returns></returns>
        public static bool RegistrarSolicitudInsumo(int Numero_Solicitud, string Tipo_Solicitud, DateTime Fecha_Solicitud,
                                                    DateTime Fecha_Entrega, string Descripcion, Dictionary<int, int> DetalleInsumos)
        {
            bool exito = true;

            try
            {
                using (var data = new AdquicisionesDataContext())
                {
                    data.Connection.Open();
                    using (DbTransaction transaccion = data.Connection.BeginTransaction(IsolationLevel.ReadCommitted))
                    {
                        // Establece la transacción al a propiedad del contexto de datos.
                        data.Transaction = transaccion;

                        try
                        {

                            var temp = new AD_SolicitudInsumo();
                            temp.Numero_Solicitud = int.MinValue;
                            temp = data.AD_SolicitudInsumo.Where(x => x.Numero_Solicitud == Numero_Solicitud).ToList().DefaultIfEmpty(temp).FirstOrDefault();
                            temp.Tipo_Solicitud = Tipo_Solicitud;
                            temp.Fecha_Solicitud = Fecha_Solicitud;
                            temp.Fecha_Entrega = Fecha_Entrega;
                            temp.Estado_Solicitud = 1;
                            temp.Estado_Registro = 1;
                            temp.Descripcion = Descripcion;

                            if (temp.Numero_Solicitud == int.MinValue)
                            {
                                temp.Usuario_Creacion = "User";
                                temp.Fecha_Creacion = DateTime.Now;
                                data.AD_SolicitudInsumo.InsertOnSubmit(temp);
                                data.SubmitChanges();


                            }
                            else
                            {
                                //Se trata de una edicion
                                List<AD_DetalleSolicitudInsumo> detalleSol =
                                    data.AD_DetalleSolicitudInsumo.Where(x => x.Numero_Solicitud == Numero_Solicitud)
                                    .ToList();
                                data.AD_DetalleSolicitudInsumo.DeleteAllOnSubmit(detalleSol);
                                data.SubmitChanges();
                            }

                            var listado = new List<AD_DetalleSolicitudInsumo>();
                            foreach (KeyValuePair<int, int> detalleInsumo in DetalleInsumos)
                            {
                                var detalle = new AD_DetalleSolicitudInsumo();
                                detalle.Numero_Solicitud = temp.Numero_Solicitud;
                                detalle.Codigo_Insumo = detalleInsumo.Key;
                                detalle.Cantidad = detalleInsumo.Value;
                                detalle.Estado_DetalleSolicitud = 2;
                                listado.Add(detalle);
                            }

                            data.AD_DetalleSolicitudInsumo.InsertAllOnSubmit(listado);
                            data.SubmitChanges();

                            transaccion.Commit();
                        }
                        catch
                        {

                            transaccion.Rollback();
                            exito = false;
                        }
                        finally
                        {
                            FileLogger log = new FileLogger();
                            FileLogger.Instance.Open(@"D:\MyLog.log", true);
                            FileLogger.Instance.CreateEntry("Solicitud de Insumo:");
                            FileLogger.Instance.Close();
                        }
                    }
                }
            }
            catch
            {
                exito = false;
            }

            return exito;
        }
        /// <summary>
        /// Se listan los insumos por Código
        /// </summary>
        /// <param name="codigoInsumo">Código del Insumo</param>
        /// <returns> listado de insumo</returns>
        public static List<AD_Insumo> ListarInsumos(int codigoInsumo)
        {
            List<AD_Insumo> listado;

            using (var data = new AdquicisionesDataContext())
            {
                listado = codigoInsumo <= 0 ? data.AD_Insumo.ToList() : data.AD_Insumo.Where(x => x.Codigo_Insumo == codigoInsumo).ToList();

                return listado;
            }
            return listado;
        }

        /// <summary>
        /// Se lista las solicitudes ingresadas
        /// </summary>
        /// <param name="tipoSol">Tipo de Solicitud</param>
        /// <param name="desc">Descripcion de la Solicitud</param>
        /// <param name="fecSol">Fecha de la Solicitud</param>
        /// <returns>List<AD_SolicitudInsumo></AD_SolicitudInsumo> </returns>
        public static List<AD_SolicitudInsumo> ListadoSolicitudInsumo(string tipoSol, string desc, DateTime? fecSol)
        {
            List<AD_SolicitudInsumo> solicitud;

            using (var data = new AdquicisionesDataContext())
            {
                solicitud = data.AD_SolicitudInsumo.Where(z => z.Tipo_Solicitud == (string.IsNullOrEmpty(tipoSol) ? z.Tipo_Solicitud : tipoSol) &&
                                                               z.Fecha_Solicitud == (fecSol ?? z.Fecha_Solicitud) &&
                                                               SqlMethods.Like(z.Descripcion, String.Format("%{0}%", desc))).ToList();
            }
            return solicitud;
        }

        /// <summary>
        /// Se elimina la solicitud de insumo
        /// </summary>
        /// <param name="numeroSolicitud">Numero de la Solicitud</param>
        /// <returns>Valor del tipo booleano que indica el estado de la eliminación</returns>
        public static bool EliminarSolicitudInsumo(int numeroSolicitud)
        {
            bool exito = true;
            try
            {
                using (var data = new AdquicisionesDataContext())
                {

                    data.Connection.Open();

                    // Instancia un objeto transacción que será asignado al contexto de datos
                    DbTransaction transaccion = data.Connection.BeginTransaction(IsolationLevel.ReadCommitted);

                    // Establece la transacción al a propiedad del contexto de datos.
                    data.Transaction = transaccion;

                    try
                    {

                        //Se elimina el detalle
                        var detalleSol =
                            data.AD_DetalleSolicitudInsumo.Where(x => x.Numero_Solicitud == numeroSolicitud).ToList();

                        data.AD_DetalleSolicitudInsumo.DeleteAllOnSubmit(detalleSol);
                        data.SubmitChanges();

                        //Se elimina la acebcera
                        var solicitud = data.AD_SolicitudInsumo.FirstOrDefault(x => x.Numero_Solicitud == numeroSolicitud);
                        if (solicitud != null)
                        {
                            data.AD_SolicitudInsumo.DeleteOnSubmit(solicitud);
                            data.SubmitChanges();
                        }
                        //Se realiza la transacción
                        transaccion.Commit();
                    }
                    catch
                    {
                        transaccion.Rollback();
                        exito = false;
                    }
                    finally
                    {
                        transaccion.Dispose();
                    }

                }
            }
            catch
            {
                exito = false;
            }

            return exito;
        }

        /// <summary>
        /// Se obtiene la solicitud de insumo por numero
        /// </summary>
        /// <param name="numeroSolicitud">Número de Solicitud de Insumo</param>
        /// <returns>AD_SolicitudInsumo</returns>
        public static AD_SolicitudInsumo ObtenerSolicitudInsumo(int? numeroSolicitud)
        {
            AD_SolicitudInsumo solicitud;
            using (var data = new AdquicisionesDataContext())
            {
                solicitud = data.AD_SolicitudInsumo.FirstOrDefault(x => x.Numero_Solicitud == numeroSolicitud);
                solicitud.AD_DetalleSolicitudInsumo.Load();
            }

            return solicitud;
        }

        /// <summary>
        /// Se obtiene el stock asociado al insumo
        /// </summary>
        /// <param name="codigoInsumo">Codigo del Insumo</param>
        /// <returns>Listado de Stocks de insumo</returns>
        public static List<AD_InsumoStock> ObtenerInsumoStock(int? codigoInsumo)
        {
            var stock = new List<AD_InsumoStock>();

            using (var data = new AdquicisionesDataContext())
            {
                stock = data.AD_InsumoStock.Where(
                      x => x.Codigo_Insumo == (codigoInsumo ?? x.Codigo_Insumo)).ToList();
            }
            return stock;
        }

        /// <summary>
        /// Se obtiene la proyeccion de venta del insumo
        /// </summary>
        /// <param name="idInsumo">Código del Insumo</param>
        /// <param name="cantidadInsumo">Cantidad de Insumo</param>
        /// <param name="fechaActual">Fecha de la consulta</param>
        /// <returns>Listado de Proyección de Ventas</returns>
        public static List<AD_ProyeccionVenta> ObtenerVentaProyectada(int idInsumo, int cantidadInsumo, DateTime fechaActual)
        {
            List<AD_ProyeccionVenta> proyeccion;

            using (var data = new AdquicisionesDataContext())
            {
                proyeccion = data.AD_ProyeccionVenta.Where(
                    x =>
                    x.Codigo_Insumo == idInsumo && cantidadInsumo <= x.Cantidad_Sugerida &&
                    (fechaActual >= x.Fecha_Inicio && fechaActual <= x.Fecha_Fin)).ToList();
            }
            return proyeccion;
        }

        public static List<AD_ListadoGeneralSolicitudInsumo> ListadoOrdenCompra(int? codigoProveedor)
        {
            //var listadoSolicitudInsumo;
            using (var data = new AdquicisionesDataContext())
            {
                if (codigoProveedor == null)
                {
                    return data.ListadoGeneralSolicitudInsumo().ToList();
                }
                else
                {
                    return data.ListadoGeneralSolicitudInsumo().Where(x => x.Codigo_Proveedor == codigoProveedor).ToList();
                }


                //List<AD_ListadoOrdenCompra> consulta = (from si in data.AD_SolicitudInsumo
                //                                        join ds in data.AD_DetalleSolicitudInsumo on si.Numero_Solicitud equals ds.Numero_Solicitud
                //                                        join ins in data.AD_Insumo on ds.Codigo_Insumo equals ins.Codigo_Insumo
                //                                        join pin in data.AD_ProveedorInsumo on ins.Codigo_Insumo equals pin.Codigo_Insumo
                //                                        join pv in data.AD_Proveedor on pin.Codigo_Proveedor equals pv.Codigo_Proveedor
                //                                        select new
                //                                        {
                //                                            Codigo_Proveedor = pv.Codigo_Proveedor,
                //                                            Razon_Social = pv.Razon_Social,
                //                                            Numero_Solicitud = si.Numero_Solicitud,
                //                                            Tipo_Solicitud = si.Tipo_Solicitud,
                //                                            Fecha_Solicitud = si.Fecha_Solicitud,
                //                                            Fecha_Entrega = si.Fecha_Entrega,
                //                                            Descripcion_Solicitud = si.Descripcion,
                //                                            Codigo_Insumo = ins.Codigo_Insumo,
                //                                            Insumo = ins.Descripcion_Insumo
                //                                        }).ToList();


            }

            return null;
        }


        public static List<AD_InsumoPrecioCantidad> ObtenerSolicitudInsumoProveedor(int? codigoProveedor)
        {

            using (var data = new AdquicisionesDataContext())
            {


                var detalle = (from s in data.AD_SolicitudInsumo
                               join d in data.AD_DetalleSolicitudInsumo on s.Numero_Solicitud
                                   equals d.Numero_Solicitud
                               join p in data.AD_ProveedorInsumo on d.Codigo_Insumo equals
                                   p.Codigo_Insumo
                               join r in data.AD_Insumo on d.Codigo_Insumo equals
                                   r.Codigo_Insumo
                               where p.Codigo_Proveedor == codigoProveedor
                               && d.Numero_OC == null//lchang 040713
                               select
                                   new
                                       {
                                           CodigoInsumo = (int)d.Codigo_Insumo,
                                           Cantidad = (int)d.Cantidad,
                                           Precio = (decimal)r.Precio_Insumo,
                                           Numero_Solicitud = s.Numero_Solicitud
                                       }).ToList();

                var resultado = new List<AD_InsumoPrecioCantidad>();
                foreach (var item in detalle)
                {
                    var iterador = new AD_InsumoPrecioCantidad
                        {
                            Codigo_Insumo = item.CodigoInsumo,
                            Cantidad = item.Cantidad,
                            Precio_Insumo = item.Precio,
                            Numero_Solicitud = item.Numero_Solicitud
                        };

                    resultado.Add(iterador);
                }

                return resultado;
            }

        }

        /// <summary>
        /// Se genera la Orden de Compra
        /// </summary>
        /// <param name="orden">Objeto del Tipo Orden de Compra</param>
        /// <param name="detalle">Objeto del Tipo Detalle de Orden de Compra</param>
        /// <returns>Valor del tipo booleano que indica el estado del proceso</returns>
        public static int GenerarOrdenCompra(AD_OrdenCompra orden, List<AD_DetalleOrdenCompra> detalle)
        {
            bool exito = true;
            int numero_OC = -1;
            try
            {
                using (var data = new AdquicisionesDataContext())
                {
                    data.Connection.Open();

                    // Instancia un objeto transacción que será asignado al contexto de datos
                    DbTransaction transaccion = data.Connection.BeginTransaction(IsolationLevel.ReadCommitted);

                    // Establece la transacción al a propiedad del contexto de datos.
                    data.Transaction = transaccion;

                    try
                    {
                        data.AD_OrdenCompra.InsertOnSubmit(orden);
                        data.SubmitChanges();
                        foreach (var adDetalleOrdenCompra in detalle)
                        {
                            adDetalleOrdenCompra.Numero_OC = orden.Numero_OC;
                        }

                        data.AD_DetalleOrdenCompra.InsertAllOnSubmit(detalle);
                        data.SubmitChanges();
                        //Se realiza el commit
                        transaccion.Commit();
                    }
                    catch (Exception ex)
                    {
                        FileLogger.Instance.Open(@"D:\MyLog.log", true);
                        FileLogger.Instance.CreateEntry(ex.Message);
                        FileLogger.Instance.Close();
                        transaccion.Rollback();
                    }
                    finally
                    {
                        data.Connection.Close();
                        FileLogger.Instance.Open(@"D:\MyLog.log", true);
                        FileLogger.Instance.CreateEntry("Generación de Nro OC:" + orden.Numero_OC.ToString());
                        FileLogger.Instance.Close();
                        numero_OC = orden.Numero_OC;
                    }
                }
            }
            catch
            {
                numero_OC = -1;
            }

            return numero_OC;
        }

        /// <summary>
        /// Se obtiene la Orden de Compra máxima con estado pendiente
        /// </summary>
        /// <returns>Objeto del Tipo Orden de Compra</returns>
        public static AD_OrdenCompra ObtenerOrdenCompraMax()
        {
            AD_OrdenCompra orden;
            using (var data = new AdquicisionesDataContext())
            {
                //Se debe validar que exista una orden de compra con estado=1
                if (data.AD_OrdenCompra.Count(x => x.Estado_OC.Equals('1')) > 0)
                {
                    int maxOc = data.AD_OrdenCompra.Where(x => x.Estado_OC.Equals('1')).Max(p => p.Numero_OC);
                    orden = data.AD_OrdenCompra.FirstOrDefault(x => x.Numero_OC == maxOc);

                }
                else
                {
                    orden = null;
                }

            }

            return orden;
        }

        /// <summary>
        /// Obtiene el proveedor por Orden de Compra
        /// </summary>
        /// <param name="numeroOrden">Nro de Orden de Compra</param>
        /// <returns>Objeto del tipo proveedor</returns>
        public static AD_Proveedor ObtenerProveedorPorOrdenCompra(int numeroOrden)
        {
            AD_Proveedor proveedor;
            using (var data = new AdquicisionesDataContext())
            {
                //data.AD_DetalleOrdenCompra.Where(x=>x.Numero_OC==numeroOrden)

                proveedor = (from d in data.AD_DetalleOrdenCompra
                             join i in data.AD_ProveedorInsumo on d.Codigo_Insumo equals i.Codigo_Insumo
                             join p in data.AD_Proveedor on i.Codigo_Proveedor equals p.Codigo_Proveedor
                             where d.Numero_OC == numeroOrden
                             select p).FirstOrDefault();

            }
            return proveedor;
        }

        /// <summary>
        /// Se anula la Orden de Compra 
        /// </summary>
        /// <param name="nroOC">Nro de Orden de Compra</param>
        /// <param name="motivo">Motivo de la anulación</param>
        /// <returns>Valor del Tipo booleano que indica el estado de la anulación</returns>
        public static bool AnulacionOrdenCompra(int nroOC, string motivo)
        {
            bool exito = true;

            try
            {
                using (var data = new AdquicisionesDataContext())
                {
                    AD_OrdenCompra orden = data.AD_OrdenCompra.FirstOrDefault(x => x.Numero_OC == nroOC);
                    orden.Estado_OC = '0';
                    orden.Motivo_Anulacion = motivo;
                    data.SubmitChanges();
                }
            }
            catch
            {
                exito = false;
            }
            return exito;
        }

        /// <summary>
        /// Se asigna la Orden de Compra a las solicitudes generadas
        /// </summary>
        /// <param name="listID">Listado de ID's de las solicitudes de insumos generadas</param>
        /// <param name="nroOC">Número de la Orden de Compra</param>
        /// <returns>Valor del tipo booleano que indica el estado del proceso</returns>
        public static bool AsignarOrdenCompraSolicituInsumo(List<AD_InsumoPrecioCantidad> listado, int nroOC)
        {
            bool exito = true;
            try
            {
                using (var data = new AdquicisionesDataContext())
                {


                    var depurado = (from l in listado
                                    join d in data.AD_DetalleSolicitudInsumo on
                                        new { l.Numero_Solicitud, l.Codigo_Insumo } equals
                                        new { Numero_Solicitud = Convert.ToInt32(d.Numero_Solicitud), Codigo_Insumo = Convert.ToInt32(d.Codigo_Insumo) }
                                    select d).ToList();

                    //List<AD_DetalleSolicitudInsumo> listadoDetalle = data.AD_DetalleSolicitudInsumo.Where(x => listID.Contains((int)x.Numero_Solicitud)).ToList();
                    foreach (var item in depurado)
                    {
                        item.Numero_OC = nroOC;
                        item.Estado_DetalleSolicitud = 2;
                    }
                    data.SubmitChanges();
                }
            }
            catch
            {
                exito = false;
            }
            return exito;
        }

        /// <summary>
        /// Se obtiene el detalle de la ORden de compra
        /// </summary>
        /// <param name="nroOC">Número de Orden de Compra</param>
        /// <returns>Listado del Tipo detalle de Orden de Compra</returns>
        public static List<AD_DetalleOrdenCompra> ObtenerDetalleOrdenCompra(int nroOC)
        {
            List<AD_DetalleOrdenCompra> detalleOrden;

            using (var data = new AdquicisionesDataContext())
            {
                detalleOrden = data.AD_DetalleOrdenCompra.Where(x => x.Numero_OC == nroOC).ToList();
            }
            return detalleOrden;
        }

        /// <summary>
        /// Se obtiene el detalle de los insumos pendientes del proveedor
        /// </summary>
        /// <param name="codigoProveedor">Código del Proveedor</param>
        /// <returns>Lista del tipo Detalle de Solicitud de Insumo</returns>
        public static List<AD_DetalleSolicitudInsumo> ObtenerDetalleSolicitudInsumoxProveedor(int? codigoProveedor)
        {
            List<AD_DetalleSolicitudInsumo> listado;
            using (var data = new AdquicisionesDataContext())
            {
                listado = (from d in data.AD_DetalleSolicitudInsumo
                           join p in data.AD_ProveedorInsumo on d.Codigo_Insumo equals p.Codigo_Insumo
                           where p.Codigo_Proveedor == codigoProveedor
                           && d.Numero_OC == null
                           select d).ToList();
            }
            return listado;
        }

        /// <summary>
        /// Se obtiene la información del Proveedor
        /// </summary>
        /// <param name="codigoProveedor">Código del Proveedor</param>
        /// <returns>Objeto del Tipo Proveedor</returns>
        public static AD_Proveedor ObtenerProveedor(int codigoProveedor)
        {
            AD_Proveedor proveedor;
            using (var data = new AdquicisionesDataContext())
            {
                proveedor = data.AD_Proveedor.FirstOrDefault(x => x.Codigo_Proveedor == codigoProveedor);
            }

            return proveedor;
        }
        /// <summary>
        /// Se valida si la solicitud se encuentra generada en una OC
        /// </summary>
        /// <param name="nroSol">Número de la Solicitud de Insumo</param>
        /// <returns>Valor del tipo booleano que indica el estado de la solicitud</returns>
        public static bool ValidarEstadoSolicitudInsumo(int nroSol)
        {
            bool exito=true;
            using (var data = new AdquicisionesDataContext())
            {
                int cantidad = data.AD_DetalleSolicitudInsumo.Where(x => x.Numero_Solicitud == nroSol && x.Numero_OC != null).Count();
                if(cantidad>0)exito=false;

            }
            return exito;
        }

    }
}
